//原型链的顶层就是Object.prototype，而这个对象的是没有原型对象的。
/**
prototype和__proto__的区别
prototype是函数才有的属性
__proto__是个每个对象都有的属性,函数也是对象
大多数情况下，__proto__可以理解我'构造器的原型'
__proto__=constructor.prototype(除了Object.create创建的对象)
*/
let a = {}; //字面量对象
console.log(a.prototype); //undefined 函数才有prototype属性
console.log(a.__proto__); //Object {} ==> function Object(){}的原型对象

let b = function() {} //字面量函数
console.log(b.prototype); // {constructor: ƒ} ==>b {}
console.log(b.__proto__); // ƒ () { [native code] } ==>function() {} /Object


// __proto__属性指向问题
//1.字面量
let a1 = {};
console.log("1.字面量");
console.log(a1.__proto__); //[Object: null prototype] {}
console.log(Object.prototype); //[Object: null prototype] {}
console.log(Object.__proto__); //ƒ () { [native code] } 方法
console.log(a1.constructor); //[Function: Object]
console.log(a1.__proto__ == Object.prototype); //true
console.log(a1.__proto__ == a1.constructor.prototype); //true
console.log(Object.prototype == a1.constructor.prototype); //true
console.log(Object == a1.constructor); //true
//2.构造方法
let B = function() {};
let b1 = new B();
console.log(b1);
console.log("2.构造方法");
console.log(b1.__proto__); //B {}
console.log(B.prototype); //B {}
console.log(B.__proto__); // f() /Object 
console.log(b1.constructor.prototype); //B{}
console.log(b1.__proto__ == B.prototype); //true
console.log(b1.__proto__ == b1.constructor.prototype); //true
console.log(B.prototype == b1.constructor.prototype); //true
console.log(B == b1.constructor); //true

//Object.create方式
console.log("3.Object.create方式");
let a2 = { a: 1 };
let a3 = Object.create(a2);
console.log(a2); //{ a: 1 };
console.log(a3); //{}
console.log(a3.__proto__); //{ a: 1 };
console.log(a3.constructor.prototype); //[Object: null prototype] {}
console.log(a2.constructor.prototype); //[Object: null prototype] {}
console.log(a2.prototype); // undefined
console.log(a2.__proto__); //[Object: null prototype] {}
console.log(a2 === a3.constructor) //false
console.log(a2 === a3.__proto__) //true  create创建的 将以a2作为__proto__
console.log(a2.__proto__ === a3.constructor.prototype) //true
console.log(a3.__proto__ === a3.constructor.prototype)
    // 重点是这个   false






//什么是原型链
//__protro是任何事物都有的属性，js万物皆对象，对形成__proto__的链条，
//递归访问__proto__必须最终到头，并且值是null
//js引擎查找对象属性时，先查找对象本身是否存在该属性，
//如果不存在，会在原型链上查找，但不会找自身的prototype(可能没有)
//所以要清楚__proto__指向
console.log("原型链");
var A = function() {};
var a9 = new A();
console.log(a9.__proto__); // A{}
console.log(A.prototype); //A{}
console.log(A.__proto__); //ƒ () { [native code] }
console.log(a9.__proto__ == A.prototype); //true

console.log(A.prototype.__proto__); //[Object: null prototype] {}==> function Object(){}
console.log(a9.__proto__.__proto__); //[Object: null prototype] {}==> function Object(){}
console.log(A.prototype.__proto__ == a9.__proto__.__proto__); //true
// console.log(Object.is(a, b))
console.log(a9.__proto__.__proto__); // //[Object: null prototype] {}==> function Object(){}

console.log(a9.__proto__.__proto__.__proto__);
//null function object 顶级object  null


// Person.prototype 和 Function.prototype
//构造函数Person的原型对象 构造函数Function的原型对象
//说明是构造函数Object的实例
//Persopn.prototype和Function.prototype两的__proto__都指向
//Object.prototype
function Person() {}
console.log(Person.prototype.__proto__ == Object.prototype);
console.log(Function.prototype.__proto__ == Object.prototype);
//__proto__的路径叫做原型链
//原型链的终点
//console.log(Person.prototype.__proto__ == Object.prototype);
//原型继承 =>
//实例可以使用构造函数上的prototype (constructor.prototype/__proto__）中的方法
//实例可以用原型链上的函数  
function Person(name) { //构造函数
    this.name = name;
}
Person.prototype.sayName = function() { //往原型对象添加方法
        console.log(this.name);
    }
    // 使用构造函数的prototype中的方法
const person = new Person("林三心");
person.sayName();

//A instanceof B 
//object instanceof constructor
//判断B的prototype是否在A的原型链上
console.log(Person instanceof Function);
console.log(Person instanceof Object);
console.log(person instanceof Person);
console.log(person instanceof Object);
//题目一
var F = function() {};
Object.prototype.a = function() {
    console.log('a');
};
Function.prototype.b = function() {
    console.log('b');
}
var f = new F();
f.a(); //a
f.b(); //f.b is not a function
F.a(); //a
F.b(); //b

var A = function() {};
A.prototype.n = 1;
var b = new A();
A.prototype = {
    n: 2,
    m: 3
}
var c = new A();

console.log(b.n); //1
console.log(b.m); //undefined
console.log(b.__proto__); //{n:1}
console.log(c.n); //2
console.log(c.m); //3
console.log(c.__proto__);
//答案为1,undefined,2,3。原因是b继承A,所以b.n就为1，而m在A中找不到，所以为undefined，以此类推，c继承的时候A添加了n和m,所以c.n和c.m分别是2和3；
var foo = {},
    F = function() {};
Object.prototype.a = 'value a';
Function.prototype.b = 'value b';

console.log(foo.a); //value a
console.log(foo.b); //undefined

console.log(F.a); //value a
console.log(F.b); //value b

function A() {}

function B(a) {
    this.a = a;
}

function C(a) {
    if (a) {
        this.a = a;
    }
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;

console.log(new A().a); //1
console.log(new B().a); //undefined B()的构造函数
console.log(new C(2).a); //2

// console.log(123['toString'].length + 123)
/**
 * 节流
 * 也就是说在规定的时间内，函数只能被调用一次，且是最先被触发调用的那次。
 * 应用场景：滚动加载更多，搜索框联想功能 高频点击 表单重复提交
 * *@param fn要被节流的函数
 *  @param delay规定的时间
 */
function throttle(fn, delay) {
    //记录上一次函数触发的时间
    var lastTime = 0;
    return function() {
        //记录当前函数触发的时间
        var nowTime = Date.now();
        if (nowTime - lastTime > delay) {
            //修正this指向问题
            fn.call(this);
            //同步执行结束时间
            lastTime = nowTime;
        }
    }
}

/**
 * 防抖
 * 多次触发事件，事件处理函数只能执行一次，并且是在触发操作结束时执行
 * 定义一个时间，这段时间再触发，延后执行，没有被触发，执行
 * 使用场景
 * 搜索框搜索输入，并在输入完以后自动搜索、手机号，邮箱验证输入检测、窗口大小 resize 变化后，再重新渲染。
 */